﻿using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using Microsoft.Win32;
using Easycmd;
using System.Threading;

namespace Easycmd{
    
    class CmdNewInstance: CmdRunner
    {
        public CmdNewInstance()
        {
            Cmd = Application.ExecutablePath;            
            UseShellExecute = true;
        }
    }
    class CmdExplorer: CmdRunner
    {
        public CmdExplorer(string dir)
        {
            Cmd = dir;            
            UseShellExecute = true;
        }
    }
    class CmdEditText : CmdRunner
    {
        public CmdEditText(string textFileName)
        {
            Cmd = GetDefaultTextEditor();
            Arguments = FileUtils.GetNameOnly(textFileName);
            WorkDir = FileUtils.GetDir(textFileName);
            UseShellExecute = true;
        }
        private string GetDefaultTextEditor()
        {
            string cmd = null;
            const string txtkey = @"HKEY_CLASSES_ROOT\.txt";
            string editorkey = @"HKEY_CLASSES_ROOT\";
            string keyvalue = (string)Registry.GetValue(txtkey, "", "");
            editorkey += keyvalue + @"\shell\open\command";
            Registry.GetValue(editorkey, "", "");
            cmd = (string)Registry.GetValue(editorkey, "", "");
            cmd = cmd.Replace("%1", "");
            cmd = cmd.TrimEnd(new char[2] { '"', ' ' });
            cmd = cmd.TrimStart(new char[2] { '"', ' ' });
            return cmd;
        }
    }
    internal class TortoiseSVNHelper
    {
        private const string TortoiseSVNCommandRegistryKey = @"svn\shell\open\command";
        internal static string GetTortoiseSVNPathFromRegistry()
        {
            string path = (string)Registry.GetValue(Path.Combine(Registry.ClassesRoot.Name, TortoiseSVNCommandRegistryKey), "", "");
            // path:
            // C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe /command:repobrowser /path:"%1"

            if (path != null)
            {
                // get the index of the "/command:" and trim it
                int index = path.LastIndexOf("/command:");
                // we get only the:
                // C:\Program Files\TortoiseSVN\bin\TortoiseProc.exe
                path = path.Substring(0, index).Trim();
                if (File.Exists(path))
                {
                    return path;
                }
            }
            return null;
        }


    }
    class CmdSvnUpdate: CmdRunner
    {
        public CmdSvnUpdate(string dir)
        {            
            
            Cmd = TortoiseSVNHelper.GetTortoiseSVNPathFromRegistry();
            if (!Util.CheckError(string.IsNullOrEmpty(Cmd), "Install tortoiseSVN first !"))
            {
                WorkDir = dir;
                UseShellExecute = true;
                Arguments =  string.Format("/command:update /rev:{0} /closeonend:{1} /path:\"{2}\"", "HEAD", 0, dir);
            }
             
            /*
            Cmd = "\"C:\\Program Files\\1000tools\\SlikSvn\\svn.exe\"";            
            Arguments = "commit ";
            Visible = true;
             */
        }
        
    }
    class CmdSvnCommit : CmdRunner
    {
        public CmdSvnCommit(string dir)
        {
            Cmd = TortoiseSVNHelper.GetTortoiseSVNPathFromRegistry();
            if (!Util.CheckError(string.IsNullOrEmpty(Cmd), "Install tortoiseSVN first !"))
            {
                WorkDir = dir;
                UseShellExecute = true;
                Arguments = string.Format("/command:commit /closeonend:{0} /path:\"{1}\"", 0, dir);
            }
        }       
    }
    class CmdMove : CmdRunner
    {
        public CmdMove(string src, string dst)
        {
            Cmd = "cmd ";
            Arguments = string.Format("/c move /y  \"{0}\" \"{1}\"", src, dst);
        }
    }
    /*
    class CmdCopy : CmdRunner
    {
        public CmdCopy(string src, string dst)
        {
            Cmd = "xcopy";
            if (Directory.Exists(src))
                Arguments = string.Format("/s  /y /f /i \"{0}\" \"{1}\"", src, dst);
            else
                // 如果是文件，不要递归（去掉S选项），否则的话
                // 执行c:\a\123.txt文件的拷贝，期望是拷贝c:\a\123.txt
                // 实际上同时会拷贝c:\a\b\123.txt,c:\a\b\c\123.txt,
                // 这不是我们希望的
                Arguments = string.Format("/y /f /i {0} {1}", src, dst);
        }
    }
     */
    [Obsolete]
    class CopyCmd:ThreadWorkerHost
    {
        CopyConfirm confirm = CopyConfirm.NoSet;
        ThreadWorker worker = null;
        string srcDir;

        public string SrcDir
        {
            get { return srcDir; }
            set { srcDir = value; }
        }
        string dstDir;

        public string DstDir
        {
            get { return dstDir; }
            set { dstDir = value; }
        }
        string [] fileName;

        public string[] FileName
        {
            get { return fileName; }
            set { fileName = value; }
        }
        CopyProcessForm processForm;

        public CopyProcessForm ProcessForm
        {
            get { return processForm; }
            set { processForm = value; }
        }
            
        public CopyCmd(int FileCount )
        {            
            worker = new ThreadWorker(this,FileCount);            
        }
        public void CancelWork()
        {
            worker.Cancel();
        }
        string CurrFrom;
        string CurrTo;
        private  void CopyFileToFile(string src, string dst)
        {
            bool overwrite = false;
            if (File.Exists(dst))
            {
                if (confirm == CopyConfirm.NoSet || confirm == CopyConfirm.Yes || confirm == CopyConfirm.No)
                    confirm = GetCopyConfirm(src, dst);
                //if (confirm == CopyConfirm.NoToAll || confirm == CopyConfirm.No)
                if (confirm == CopyConfirm.NoToAll)
                    throw new Exception("User Stop !");
                else if (confirm == CopyConfirm.YesToAll || confirm == CopyConfirm.Yes)
                    overwrite = true;
            }
            if (confirm != CopyConfirm.No)
            {
                FileUtils.DropReadOnly(dst);
                FileCopyProgress(src, dst, overwrite);
            }
            CurrFrom = src;
            CurrTo = dst;
            worker.Progress(1);            
        }

        private  void FileCopyProgress(string src, string dst, bool overwrite)
        {
            File.Copy(src, dst, overwrite);
            //Copy(src, dst, overwrite, 1024);
        }
        public  void Copy(string sourcePath, string destPath, bool overwrite, int bufferSize)
        {
            int MaxProgress =100;
            if (!overwrite && File.Exists(destPath))
                return;

            if (!Directory.Exists(Path.GetDirectoryName(destPath)))
                Directory.CreateDirectory(Path.GetDirectoryName(destPath));

            FileStream tmp_fr = new FileStream(sourcePath, FileMode.Open);
            FileStream tmp_fw = new FileStream(destPath, FileMode.Create);

            long fileSize = new FileInfo(sourcePath).Length;
            if (fileSize < bufferSize)
                bufferSize = (int)fileSize;
            long numOfLoops = (fileSize / bufferSize);
            int Step = MaxProgress / (int)numOfLoops;
            byte[] tmp_data;
            for (int a = 0; a < numOfLoops; a++)
            {
                tmp_data = new byte[bufferSize];
                tmp_fr.Read(tmp_data, 0, bufferSize);
                tmp_fw.Write(tmp_data, 0, bufferSize);
                //tmp_pb.PerformStep();
                //worker.Progress2(MaxProgress,Step);
                //Application.DoEvents();
                processForm.Text = Step.ToString();
                Application.DoEvents();
            }
            int leftBytes = (int)(fileSize - tmp_fr.Position);
            if (leftBytes > 0)
            {
                tmp_data = new byte[leftBytes];
                tmp_fr.Read(tmp_data, 0, leftBytes);
                tmp_fw.Write(tmp_data, 0, leftBytes);
            }
            tmp_fr.Close();
            tmp_fw.Flush();
            tmp_fw.Close();
            
        }
        

        private CopyConfirm GetCopyConfirm(string src, string dst)
        {
            string tip = string.Format("source file:{0},\ndestinct file : {1},\n override ?", src, dst);
            CopyConfirmForm form = new CopyConfirmForm(tip);
            form.ShowDialog();
            return form.confirm;
        }
        private void CopyFolderToFolder(string sourceFolder, string destFolder)
        {
            if (!Directory.Exists(destFolder))
                Directory.CreateDirectory(destFolder);
            string[] files = Directory.GetFiles(sourceFolder);
            foreach (string file in files)
            {
                string name = Path.GetFileName(file);
                string dest = Path.Combine(destFolder, name);
                CopyFileToFile(file, dest);
            }
            string[] folders = Directory.GetDirectories(sourceFolder);
            foreach (string folder in folders)
            {
                string name = Path.GetFileName(folder);
                string dest = Path.Combine(destFolder, name);
                CopyFolderToFolder(folder, dest);
            }
        }
        internal void Run()
        {
            worker.Run();
        }
        /*
        internal string CopyItem(string SrcDir, string DstDir, string Name)
        {            
            Name = FileUtils.CheckSlash(SrcDir) + Name;
            string dst = "";
            string srcName = (new DirectoryInfo(Name).Name);
            if (Directory.Exists(Name))
            {
                dst = FileUtils.CheckSlash(DstDir) + srcName + "\\";
                CopyFolderToFolder(Name, dst);
            }
            else
            {
                dst = FileUtils.CheckSlash(DstDir) + srcName;
                CopyFileToFile(Name, dst);
            }
            return Name;
        }
        */
        #region ThreadWorkerHost Members

        public void ProgressChanged(int percent)
        {
            processForm.UpdateProcess(CurrFrom, CurrTo);            
        }

        public void RunProc(ThreadWorker worker)
        {
            try
            {
                foreach (string fileName1 in FileName)
                {
                    if (worker.IsCanceling())
                        throw new Exception("User Cancel"); 
                    string fileName = FileUtils.CheckSlash(SrcDir) + fileName1;
                    string dst = "";
                    string srcName = (new DirectoryInfo(fileName).Name);
                    if (Directory.Exists(fileName))
                    {
                        dst = FileUtils.CheckSlash(DstDir) + srcName + "\\";
                        CopyFolderToFolder(fileName, dst);
                    }
                    else
                    {
                        dst = FileUtils.CheckSlash(DstDir) + srcName;
                        CopyFileToFile(fileName, dst);
                    }
                    
                }
            }
            catch (Exception ex  )
            {
                MessageBox.Show(ex.Message);
                return;
            }
        }

        public void Completed(bool isCancel)
        {
            processForm.SetCloseEnable(true);
            processForm.SetCancelEnable(true);
            if (isCancel)
                MessageBox.Show("User break ");
        }

        #endregion



        #region ThreadWorkerHost Members

        void ThreadWorkerHost.Progress2(int MaxProgress, int Step)
        {
            processForm.Text = string.Format("{0}/{1}", Step, MaxProgress);
        }

        #endregion
    }
    class CmdDosDir : CmdRunner
    {
        public CmdDosDir(string toDir)
        {
            Cmd = "cmd";            
            Arguments = "";
            WorkDir = toDir;
            UseShellExecute = true ;
        }
    }

    class CmdRunner
    {
        private string workDir;

        public string WorkDir
        {
            get { return workDir; }
            set { workDir = value; }
        }
        private string fullCmd = null;

        public string FullCmd
        {
            get { return fullCmd; }
            set { fullCmd = value; }
        }
        private string stdOut = null;
        public string StdOut
        {
            get { return stdOut; }
            set { stdOut = value; }
        }
        string cmd;

        public string Cmd
        {
            get { return cmd; }
            set { cmd = value; }
        }
        string arguments;

        public string Arguments
        {
            get { return arguments; }
            set { arguments = value; }
        }
        public void Run()
        {
            //fullCmd = cmd + " " + arguments;
            stdOut = CaptureOutputOfCmd();
        }
        private bool visible = false;

        public bool Visible
        {
            get { return visible; }
            set { visible = value; }
        }
        private bool useShellExecute = false;

        public bool UseShellExecute
        {
            get { return useShellExecute; }
            set { useShellExecute = value; }
        }
        private string CaptureOutputOfCmd()
        {
            StreamReader outputReader = null;
            StreamReader errorReader = null;

            try
            {
                //Create Process Start information
                ProcessStartInfo processStartInfo =
                    //new ProcessStartInfo(txtExecutable.Text.Trim(), txtParameter.Text.Trim());
                    //new ProcessStartInfo(cmd, FileUtils.GetNameOnly(arguments));
                    new ProcessStartInfo(cmd, arguments);
                processStartInfo.ErrorDialog = false;
                processStartInfo.UseShellExecute = useShellExecute;
                if (!useShellExecute)
                {
                    processStartInfo.RedirectStandardError = true;
                    processStartInfo.RedirectStandardInput = true;
                    processStartInfo.RedirectStandardOutput = true;
                    //processStartInfo.WindowStyle = ProcessWindowStyle.Minimized;
                    processStartInfo.CreateNoWindow = !visible;

                }
                //processStartInfo.WorkingDirectory = FileUtils.GetDir(arguments);
                processStartInfo.WorkingDirectory = workDir;
                //Execute the process
                Process process = new Process();
                process.StartInfo = processStartInfo;
                bool processStarted = process.Start();
                if (processStarted && !useShellExecute)
                {
                    //Get the output stream
                    outputReader = process.StandardOutput;
                    errorReader = process.StandardError;
                    process.WaitForExit();

                    //Display the result
                    string displayText =  Environment.NewLine + "==============" + Environment.NewLine;
                    displayText += outputReader.ReadToEnd();
                    string errorText = errorReader.ReadToEnd();
                    if (!string.IsNullOrEmpty(errorText) )
                        errorText = Environment.NewLine + "Error" + Environment.NewLine + "==============" +
                                   Environment.NewLine + errorText ;
                    
                    return displayText+errorText;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                if (outputReader != null)
                {
                    outputReader.Close();
                }
                if (errorReader != null)
                {
                    errorReader.Close();
                }
            }
            return "";
        }
    }

}

